/**
 * @description 资源管理类
 * @date 2024.9.10
 * @author wz
 * @midify 2025.5.9
 * @editor wz
 */


import { Asset, assetManager, AssetManager, Constructor } from "cc";
import { Singleton } from "../../utils/Singleton";

/**
 * 资源管理类，用于加载和管理资源
 */
export class ResMgr extends Singleton {

    /**
     * 加载bundle
     * @param name bundle名称
     * @returns Promise<AssetManager.Bundle> 返回一个Promise，解析为加载的bundle
     */
    private _getBundle(name: string): Promise<AssetManager.Bundle> {
        return new Promise<AssetManager.Bundle>((resolve, reject) => {
            const bundle = assetManager.getBundle(name)
            if (bundle) return resolve(bundle)
            assetManager.loadBundle(name, (err, data) => {
                if (!err)
                    resolve(data)
                else
                    reject(err)
            })

        })
    }

    /**
     * 加载bundle中的单个资源
     * @param bundle 要加载资源的bundle
     * @param path 资源路径
     * @param type 资源类型
     * @returns Promise<T> 返回一个Promise，解析为加载的资源
     */
    private async _getBundleRes<T extends Asset>(bundle: AssetManager.Bundle, path: string, type: Constructor<T>) {
        return new Promise<T>((resolve, reject) => {
            const res = bundle.get(path, type)
            if (res) return resolve(res)
            bundle.load(path, type, (err, data) => {
                if (!err) {
                    resolve(data)
                }
                else
                    reject(err)
            })
        })
    }

    /**
     * 加载资源
     * @param path 资源路径
     * @param type 资源类型
     * @param bundleName bundle名称，默认为'resources'
     * @returns Promise<T> 返回一个Promise，解析为加载的资源
     */
    async load<T extends Asset>(path: string, type: Constructor<T>, bundleName: string = 'resources'): Promise<T> {
        let bundle = await this._getBundle(bundleName)
        return this._getBundleRes(bundle, path, type)
    }

    /**
     * 加载文件夹资源
     */
    async loadDir(path: string, bundleName: string = 'resources') {
        let bundle = await this._getBundle(bundleName)
        return new Promise<Asset[]>((resolve, reject) => {
            bundle.loadDir(path, (err, res) => {
                if (!err) {
                    resolve(res)
                } else {
                    reject(err)
                }
            })
        })
    }

    /**
     * 加载bundle中的所有资源(主要用于在进游戏之前预加载)
     * @param bundleName 
     */
    async loadAll(bundleName: string = 'resources') {
        let bundle = await this._getBundle(bundleName)
        await bundle.getDirWithPath('').map(a => this.load(a.path, Asset, bundleName))
    }

    /**
     * 获取资源
     * @param path 
     * @param bundleName 
     * @returns 
     */
    getRes(path: string, bundleName: string = 'resources') {
        return assetManager.getBundle(bundleName)?.get(path);
    }
}

// 资源管理器实例
export const resMgr: ResMgr = ResMgr.getInstance<ResMgr>();